package org.jeecg.modules.villageCadreAssist.controller;

import java.io.*;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import java.net.URLDecoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.system.util.CheckIdCard;
import org.jeecg.modules.system.util.SecurityUtil;
import org.jeecg.modules.villageCadreAssist.entity.VcaDeath;
import org.jeecg.modules.villageCadreAssist.entity.VcaResident;
import org.jeecg.modules.villageCadreAssist.service.IVcaDeathService;
import org.jeecg.modules.villageCadreAssist.service.IVcaResidentService;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;

import org.jeecg.modules.villageCadreAssist.util.CommonUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.jeecg.common.system.base.controller.JeecgController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import com.alibaba.fastjson.JSON;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.jeecg.common.aspect.annotation.AutoLog;

 /**
 * @Description: vca_resident
 * @Author: jeecg-boot
 * @Date:   2022-02-13
 * @Version: V1.0
 */
@Api(tags="vca_resident")
@RestController
@RequestMapping("/villageCadreAssist/vcaResident")
@Slf4j
public class VcaResidentController extends JeecgController<VcaResident, IVcaResidentService> {
	@Autowired
	private IVcaResidentService vcaResidentService;
	@Autowired
	private IVcaDeathService vcaDeathService;

	/**
	 * 分页列表查询
	 *
	 * @param vcaResident
	 * @param pageNo
	 * @param pageSize
	 * @param req
	 * @return
	 */
	@ApiOperation(value="vca_resident-分页列表查询", notes="vca_resident-分页列表查询")
	@GetMapping(value = "/list")
	public Result<?> queryPageList(VcaResident vcaResident,
								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
								   HttpServletRequest req) {
		String firstLetter = vcaResident.getFirstLetter();
		if(StringUtils.isNotEmpty(firstLetter)){
			if(firstLetter.matches("^[a-zA-Z]+$")){
				vcaResident.setFirstLetter(firstLetter.toLowerCase()+"*");
			}else{
				vcaResident.setFirstLetter(null);
				vcaResident.setResidentName(firstLetter+"*");//支持模糊查询
			}
		}
		QueryWrapper<VcaResident> queryWrapper = QueryGenerator.initQueryWrapper(vcaResident, req.getParameterMap());
		Page<VcaResident> page = new Page<VcaResident>(pageNo, pageSize);
		String orgCode = CommonUtil.checkOrgCode(vcaResident);
		IPage<VcaResident> pageList = vcaResidentService.queryPageList(page, queryWrapper, orgCode);
		int nowYear = LocalDate.now().getYear();
		List<VcaResident> deathResidentList = new ArrayList<>();
		pageList.getRecords().forEach(item->{
			if(item.getDeath()==1){
				deathResidentList.add(item);
			}else{
				item.setYear(nowYear - item.getBirthday()/10000);
			}
		});
		if(deathResidentList.size()>0){//死亡人员的年龄需要根据死亡时间计算
			Map<Integer, VcaResident> residentMap = deathResidentList.stream().collect(Collectors.toMap(VcaResident::getId, item -> item));
			List<VcaDeath> deathList = vcaDeathService.list(new LambdaQueryWrapper<VcaDeath>().in(VcaDeath::getResidentId, residentMap.keySet()));
			ZoneId zoneId = ZoneId.systemDefault();
			deathList.forEach(item->{
				VcaResident resident = residentMap.get(item.getResidentId());
				LocalDate deathDate = item.getDeathTime().toInstant().atZone(zoneId).toLocalDate();
				resident.setYear(deathDate.getYear() - resident.getBirthday()/10000);
			});
		}
		return Result.OK(pageList);
	}

	/**
	 *   添加
	 *
	 * @param vcaResident
	 * @return
	 */
	@AutoLog(value = "vca_resident-添加")
	@ApiOperation(value="vca_resident-添加", notes="vca_resident-添加")
	@PostMapping(value = "/add")
	@RequiresPermissions("vcaResident:add")
	public Result<?> add(@RequestBody VcaResident vcaResident) {
		vcaResidentService.save(vcaResident);
		return Result.OK("添加成功！");
	}

	/**
	 *  编辑
	 *
	 * @param vcaResident
	 * @return
	 */
	@AutoLog(value = "vca_resident-编辑")
	@ApiOperation(value="vca_resident-编辑", notes="vca_resident-编辑")
	@PutMapping(value = "/edit")
	@RequiresPermissions("vcaResident:edit")
	public Result<?> edit(@RequestBody VcaResident vcaResident) {
		vcaResidentService.updateById(vcaResident);
		return Result.OK("编辑成功!");
	}



	/**
	 *   通过id删除
	 *
	 * @param id
	 * @return
	 */
	@AutoLog(value = "vca_resident-通过id删除")
	@ApiOperation(value="vca_resident-通过id删除", notes="vca_resident-通过id删除")
	@DeleteMapping(value = "/delete")
	@RequiresPermissions("vcaResident:delete")
	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
		vcaResidentService.removeById(id);
		return Result.OK("删除成功!");
	}

	/**
	 *  批量删除
	 *
	 * @param ids
	 * @return
	 */
	@AutoLog(value = "vca_resident-批量删除")
	@ApiOperation(value="vca_resident-批量删除", notes="vca_resident-批量删除")
	@DeleteMapping(value = "/deleteBatch")
	@RequiresPermissions("vcaResident:deleteBatch")
	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
		this.vcaResidentService.removeByIds(Arrays.asList(ids.split(",")));
		return Result.OK("批量删除成功!");
	}

	/**
	 * 通过id查询
	 *
	 * @param id
	 * @return
	 */
	@ApiOperation(value="vca_resident-通过id查询", notes="vca_resident-通过id查询")
	@GetMapping(value = "/queryById")
	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
		VcaResident vcaResident = vcaResidentService.getById(id);
		if(vcaResident==null) {
			return Result.error("未找到对应数据");
		}
		return Result.OK(vcaResident);
	}

	 @ApiOperation(value="vca_resident-根据姓名首字母大写或是姓名查询", notes="vca_resident-根据姓名首字母大写或是姓名查询")
	 @GetMapping(value = "/queryTopN")
	 public Result<?> queryTopN(LoginUser user,String firstLetter,String orgCode) {
		 if(firstLetter.length()<2) return Result.error("至少输入两个字符");
		 VcaResident resident = new VcaResident();
		 if(firstLetter.matches("^[a-zA-Z]+$")){
			 resident.setFirstLetter(firstLetter.toLowerCase());
		 }else{
			 resident.setFirstLetter(null);
			 resident.setResidentName(firstLetter);
		 }
		 if(orgCode == null || !orgCode.startsWith(user.getOrgCode()))
			 orgCode = user.getOrgCode();
		 List<VcaResident> list = vcaResidentService.queryTopN(resident,orgCode);

		 return Result.OK(list);
	 }

    /**
    * 导出excel
    *
    * @param request
    * @param vcaResident
    */
    @RequestMapping(value = "/exportXls")
	@RequiresPermissions("vcaResident:exportXls")
    public ModelAndView exportXls(HttpServletRequest request, VcaResident vcaResident) {
        return super.exportXls(request, vcaResident, VcaResident.class, "vca_resident");
    }

    /**
      * 通过excel导入数据
    *
    * @param request
    * @param response
    * @return
    */
    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
	@RequiresPermissions("vcaResident:importExcel")
    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
		List<VcaResident> residentList = super.importExcel(request, VcaResident.class);

		vcaResidentService.batchSave(residentList);

		return Result.OK(residentList.size());
    }




	 @AutoLog(value = "vca_resident-分配")
	 @ApiOperation(value="vca_resident-分配", notes="vca_resident-分配")
	 @PostMapping(value = "/distribute")
//	 @RequiresPermissions("vcaResident:add")
	 public void distribute(MultipartHttpServletRequest multipartRequest, HttpServletResponse response) {
		try(OutputStream outputStream = response.getOutputStream()){
			Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
			for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
				MultipartFile file = entity.getValue();
				try{
					String filename = file.getOriginalFilename();
					Workbook workbook;
					if (filename.endsWith("xls")) {
						workbook = new HSSFWorkbook(file.getInputStream());
					} else if(filename.endsWith("xlsx")){
						workbook = new XSSFWorkbook(file.getInputStream());
					}else{
						throw new RuntimeException("不支持该类型文件");
					}
					Sheet sheet = workbook.getSheetAt(0);

					int lastRowNum = sheet.getLastRowNum();
					int maxColumn = 0;//最大列数
					List<Row> headList = new ArrayList<>(16);
					int idcardColumn = -1;
					row:for (int i = 0; i < lastRowNum; i++) {//遍历头部
						Row row = sheet.getRow(i);
						short lastCellNum = row.getLastCellNum();
						if(lastCellNum>maxColumn)
							maxColumn=lastCellNum;
						for (int j = 0; j < lastCellNum; j++) {
							Cell cell = row.getCell(j);
							if(isIdcard(cell) && isIdcard(sheet.getRow(i+1).getCell(j))){//当行是身份证，下一行该列还是身份证，说明这行是数据行
								idcardColumn = j;
								break row;
							}
						}
						if(i>10){//只遍历前10行
							break;
						}
						headList.add(row);
					}
					if(idcardColumn==-1){
						throw new RuntimeException("无身份证列，无法分配");
					}

					Map<String,Row> dataMap = new LinkedHashMap<>(sheet.getLastRowNum());
					for (int i = headList.size(); i < lastRowNum; i++) {
						Row row = sheet.getRow(i);
						dataMap.put(row.getCell(idcardColumn).getStringCellValue().trim(),row);
					}
					doDistribute(workbook,headList,dataMap,maxColumn);
					workbook.removeSheetAt(0);
					response.setContentType("application/octet-stream");
					response.setHeader("content-disposition","attachment;fileName="+filename);
//				 FileOutputStream outputStream = new FileOutputStream("E://testttt.xlsx");
//				 workbook.write(outputStream);
//				 outputStream.close();
//				 OutputStream outputStream = response.getOutputStream();
					workbook.write(outputStream);
					outputStream.flush();
					workbook.close();
				}catch (Exception e){
					e.printStackTrace();
				}
				break;//只处理上传的第一个file
			}
		}catch (Exception e){
			e.printStackTrace();
		}
	 }

	 private void doDistribute(Workbook workbook,List<Row> headList,Map<String,Row> dataMap,Integer maxColumn){
		 LoginUser loginUser = SecurityUtil.getLoginUser();
		 List<Map<String,String>> mapList = vcaResidentService.queryVillageCadreList(dataMap.keySet(),loginUser.getOrgCode());
		 Map<String,String> idcardMap = new HashMap<>(mapList.size());
		 mapList.stream().forEach(item->{
			 idcardMap.put(item.get("idcard"),item.get("realname"));
		 });
		 CellStyle borderCellStyle = createCellStyle(workbook);
		 CellStyle borderBoldCellStyle = createCellStyle(workbook);
		 Font font = workbook.createFont();
		 font.setBold(true);
		 borderBoldCellStyle.setFont(font);

		 //转换为 <xxx村干，负责的居民列表>模式
		 Map<String,List<Row>> villageCadreMap = new HashMap<>();
		 List<Row> noDistributeList = new ArrayList<Row>();
		 for (String idcard : dataMap.keySet()) {
			 Row row = dataMap.get(idcard);
			 String villageCadreName = idcardMap.get(idcard);
			 if(villageCadreName==null){
				 noDistributeList.add(row);
			 }else{
				 List<Row> rows = villageCadreMap.get(villageCadreName);
				 if(rows==null){
					 rows=new ArrayList<>();
					 villageCadreMap.put(villageCadreName,rows);
				 }
				 rows.add(row);
			 }
		 }
		 villageCadreMap.put("无人负责",noDistributeList);
		 //重命名 villageCadreName，添加数量
		 int headRowNum = headList.size();

		 for (String villageCadreName : villageCadreMap.keySet()) {
			 List<Row> rowList = villageCadreMap.get(villageCadreName);
			 if(rowList.size()>0){
				 //将表头也添加进来
				 Sheet sheet = workbook.createSheet(villageCadreName + "(共" + rowList.size() + "条)");
//				 rowList.addAll(0,headList);
				 for (int i = 0; i < maxColumn; i++) {//设置宽度
					 sheet.setColumnWidth(i,workbook.getSheetAt(0).getColumnWidth(i));
				 }
				 copyData(sheet,headList,0,borderBoldCellStyle);
				 copyData(sheet,rowList,headList.size(),borderCellStyle);
			 }
		 }
	 }

	 private CellStyle createCellStyle(Workbook workbook){
		 CellStyle cellStyle = workbook.createCellStyle();
		 cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
		 cellStyle.setBorderLeft(BorderStyle.THIN);//左边框
		 cellStyle.setBorderTop(BorderStyle.THIN);//上边框
		 cellStyle.setBorderRight(BorderStyle.THIN);//右边框
		 return cellStyle;
	 }

	 private void copyData(Sheet targetSheet,List<Row> rowList,Integer startRow,CellStyle cellStyle){
		 for (int i = 0; i < rowList.size(); i++) {
			 Row row = rowList.get(i);
			 Row targetRow = targetSheet.createRow(startRow+i);
			 for (int j = 0; j < row.getLastCellNum(); j++) {
				 Cell cell = row.getCell(j);
				 if(cell != null){
					 CellType cellType = cell.getCellType();
					  Cell targetCell = targetRow.createCell(j);
					 targetCell.setCellStyle(cellStyle);
					 if (cellType == CellType.STRING)
						 targetCell.setCellValue(cell.getStringCellValue());
					 else if (cellType == CellType.NUMERIC)
						 targetCell.setCellValue(cell.getNumericCellValue());
					 else if (cellType == CellType.FORMULA)
						 targetCell.setCellValue(cell.getCellFormula());
				 }
			 }
		 }
	 }

	 private static boolean isIdcard(Cell cell){
		 if(cell != null && cell.getCellType()== CellType.STRING){
			 String value = cell.getStringCellValue();
			 if(value != null){
				 value = value.trim();
				 if(value.length()==18 && CheckIdCard.check(value)){
					 return true;
				 }
			 }
		 }
		 return false;
	 }

}
